using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.Reflection;

namespace MyClever.Lib
{
    /// <summary>
    /// By using the optional "validation"-tag in your package sequence definition, you can 
    /// ensure that every content-value observe some special rules, the plugin expects to work with.
    /// For example you can define that a content-value must be:
    ///  <list type="bullet">
    /// <item>
    /// <description>from a special type (int, double, ...)</description>
    /// </item>
    /// <item>
    /// <description>contains some special characters</description>
    /// </item>
    /// <item>
    /// <description>constrains on your favorite regular expressions (isurl, ismailaddress, ...)</description>
    /// </item>
    /// <item>
    /// <description>...</description>
    /// </item>
    /// </list>
    /// Whenever you use the optional "validation"-tag for a package-column, every content-value MUST confirm with that rule(s).
    /// In short: If the validation fails, the content-value will not saved!
    /// </summary>
    public static class Validation
    {
        /// <summary>
        /// Compares the content-value with the expected length (= numbers of characters).
        /// </summary>
        /// <param name="str">The content-value you like to validate.</param>
        /// <param name="length">The expexted length. (= numbers of characters)</param>
        /// <returns><c>true</c>, if the content-value has accurately the expected length; otherwise, <c>false</c></returns>
        public static bool haslength(string str, string length) 
        {
            return (str.Length == Convert.ToInt32(length));
        }

        /// <summary>
        /// Ensures that the content-value has a minimum of characters.
        /// </summary>
        /// <param name="str">The content-value you like to validate.</param>
        /// <param name="minLength">The minimum numbers of characters you expected.</param>
        /// <returns><c>true</c>, if the content-value has at least the expected length; otherwise, <c>false</c></returns>
        public static bool hasminlength(string str, string minLength)
        {
            return (str.Length >= Convert.ToInt32(minLength));
        }

        /// <summary>
        /// Ensures that the content-value 	does not exceed a maximum of characters.
        /// </summary>
        /// <param name="str">The content-value you like to validate.</param>
        /// <param name="maxLength">The maximum numbers of characters you expected.</param>
        /// <returns><c>true</c>, if the content-value has not more than the expected length; otherwise, <c>false</c></returns>
        public static bool hasmaxlength(string str, string maxLength)
        {
            return (str.Length <= Convert.ToInt32(maxLength));
        }

        /// <summary>
        /// Ensures that the content-value is from type <see cref="double"/> or <see cref="int"/>.
        /// </summary>
        /// <param name="str">The content-value you like to validate.</param>
        /// <returns><c>false</c>, if the content-value is not numerical; otherwise, <c>true</c></returns>
        public static bool isnumeric(string str)
        {
            if (isdouble(str) || isint(str))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// Ensures that the content-value is from type <see cref="double"/>.
        /// </summary>
        /// <param name="str">The content-value you like to validate.</param>
        /// <returns><c>false</c>, if the content-value is not from type <see cref="double"/>; otherwise, <c>true</c>.</returns>
        public static bool isdouble(string str)
        {
            try 
            {
                Double.Parse(str);
                return true;
            }
            catch {} // just dismiss errors but return false 
            return false;         
        }

        /// <summary>
        /// Ensures that the content-value is from type <see cref="int"/>.
        /// </summary>
        /// <param name="str">The content-value you like to validate.</param>
        /// <returns><c>false</c>, if the content-value is not from type <see cref="int"/>; otherwise, <c>true</c>.</returns>
        public static bool isint(string str)
        {
            try
            {
                Int32.Parse(str);
                return true;
            }
            catch { } // just dismiss errors but return false 
            return false;
        }

        /// <summary>
        /// Ensures that the content-value is from type <see cref="bool"/>.
        /// </summary>
        /// <param name="str">The content-value you like to validate.</param>
        /// <returns><c>false</c>, if the content-value is not from type <see cref="bool"/>; otherwise, <c>true</c>.</returns>
        public static bool isboolean(string str)
        {
            try
            {
                Boolean.Parse(str);
                return true;
            }
            catch { } // just dismiss errors but return false 
            return false;
        }

        /// <summary>
        /// Determines whether the content-value contains the expected string.
        /// </summary>
        /// <param name="str">The content-value you like to validate.</param>
        /// <param name="pattern">The string which should be part of the content-value.</param>
        /// <returns>
        /// 	<c>true</c> if the content-value contains the specified pattern; otherwise, <c>false</c>.
        /// </returns>
        public static bool contains(string str, string pattern)
        {
            return (str.ToLower().Contains(pattern.ToLower()));
        }


        /// <summary>
        /// Compares the content-value with the expected string.
        /// </summary>
        /// <param name="str">The content-value you like to validate.</param>
        /// <param name="pattern">The string which should be the content of the content-value.</param>
        /// <returns>
        /// 	<c>true</c> if the content-value has the same value like the pattern; otherwise, <c>false</c>.
        /// </returns>
        public static bool compare(string str, string pattern)
        {
            return (0 == String.Compare(str, pattern, StringComparison.CurrentCultureIgnoreCase));
        }

        /// <summary>
        /// Ensures that the content-value is a valid URL format.
        /// </summary>
        /// <param name="str">The content-value you like to validate.</param>
        /// <returns><c>True</c> if the content-value is correctly formatted URL, otherwise <c>False</c>.</returns>
        /// <remarks></remarks>
        public static bool isurl(string str)
        {
            return Regex.IsMatch(str, @"((https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\))+[\w\d:#@%/;$()~_?\+-=\\\.&]*)");
        }

        /// <summary>
        /// Ensures that the content-value is a valid email address format (RFC 822).
        /// </summary>
        /// <param name="str">The content-value you like to validate.</param>
        /// <returns><c>True</c> if the content-value is correctly formatted email address, otherwise <c>False</c>.</returns>
        /// <remarks></remarks>
        public static bool ismailaddress(string str)
        {
            return Regex.IsMatch(str, @"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?");
        }

        public static bool ispath(string str)
        {
            Regex r = new Regex(@"^(([a-zA-Z]\:)|(\\))+\\(([\w()-][\w\s()-]*[\w()-]+)|([\w()-]+))\$?(\\(([\w()-][\w\s()-]*[\w()-]+)|([\w()-]+)))*\\?$");
            return r.IsMatch(str);
        }

        ///// <summary>
        ///// Ensures that the content-value is a valid path on a windows-machine.
        ///// </summary>
        ///// <param name="str">The content-value you like to validate.</param>
        ///// <returns><c>false</c>, if the content-value is not a valid path; otherwise, <c>true</c>.</returns>
        public static bool isexistingpath(string str)
        {
            return Directory.Exists(str);
        }

        public static bool isfile(string str)
        {
            Regex r = new Regex(@"([A-Z]:\\[^/:\*\?<>\|]+\.\w{2,6})|(\\{2}[^/:\*\?<>\|]+\.\w{2,6})");
            return r.IsMatch(str);
        }

        public static bool isexistingfile(string str)
        {
            return File.Exists(str);
        }

        public static bool isgreaterthen(string original, string then)
        {
            return (Convert.ToInt64(original) > Convert.ToInt64(then));
        }

        public static bool issmallerthen(string original, string then)
        {
            return (Convert.ToInt64(original) < Convert.ToInt64(then));
        }


        public static List<string> GetValidationMethods()
        {
            List<string> validationMethods = new List<string>();

            Type validationType = Type.GetType("MyClever.Lib.Validation");

            foreach (MethodInfo methodOn in validationType.GetMethods())
            {
                if ((true == methodOn.IsStatic) && (typeof(Boolean) == methodOn.ReturnType)
                    && methodOn.Name != "IsValid")
                {
                    validationMethods.Add(methodOn.Name);
                }
            }

            return validationMethods;
        }
    }
}
